package com.chezai.client.server.util;


import android.util.Base64;
import android.util.Log;

import com.chezai.client.bean.TerminalBaseInfo;
import com.chezai.client.dao.manager.TerminalBaseInfoDaoManager;
import com.chezai.client.global.TerminalApplication;
import com.chezai.client.utils.AESUtil;
import com.chezai.client.utils.PreferenceManager;
import com.chezai.client.utils.ToastUtil;
import com.jx.driving.message.TimeTerminalTransmissionMessage;
import com.jx.driving.message.TransmissionMessageIdMapper;
import com.jx.driving.request.Terminal0x0900Request;
import com.jx.driving.request.Terminal0x8900Request;
import com.jx.driving.request.domain.DynamicObject;
import com.jx.driving.transform.DefaultTransform;
import com.jx.driving.transform.Transform;
import com.jx.driving.util.PassUtils;

import java.io.ByteArrayInputStream;
import java.nio.ByteBuffer;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.BitSet;
import java.util.Enumeration;

import javax.crypto.Cipher;

/**
 * 建立透传连接
 * Created by LZF on 2016/8/27.
 */
public class TransmissionMessageUtil {
    private TransmissionMessageIdMapper idMapper = new TransmissionMessageIdMapper();

    public TransmissionMessageUtil() {

    }

    public TimeTerminalTransmissionMessage getTimeTerminalTransmissionMessage(Terminal0x8900Request msg) {
        Transform transform = new DefaultTransform();
        DynamicObject dynamicObject = msg.getObject();
        int id = dynamicObject.getId();
        Class<?> clazz = TransmissionMessageIdMapper.instance.getClass(id);
        byte[] content = dynamicObject.getContent();
        return (TimeTerminalTransmissionMessage) transform
                .transformToObject(new ByteArrayInputStream(content), clazz);
    }

    public TimeTerminalTransmissionMessage getTerminalTransmissionMessage(Terminal0x0900Request msg) {
        Transform transform = new DefaultTransform();
        DynamicObject dynamicObject = msg.getObject();
        int id = dynamicObject.getId();
        Class<?> clazz = TransmissionMessageIdMapper.instance.getClass(id);
        byte[] content = dynamicObject.getContent();
        return (TimeTerminalTransmissionMessage) transform
                .transformToObject(new ByteArrayInputStream(content), clazz);
    }

    /**
     * 构建上行透传对象
     *
     * @param msg
     * @param isAddMsg     true 补传消息；
     * @param isNeedAnswer true 需要服务器应答
     * @return
     */
    public Terminal0x0900Request buildTerminal0x0900Request(TimeTerminalTransmissionMessage msg, boolean isAddMsg, boolean isNeedAnswer) {

        Terminal0x0900Request req = new Terminal0x0900Request();
        DynamicObject dynamicObject = new DynamicObject();
        int id = idMapper.getId(msg.getClass());
        int extendProperties = getExt(isAddMsg, isNeedAnswer);
        Transform transform = new DefaultTransform();
        byte[] content = transform.transformObjectToByteArray(msg);
        dynamicObject.setId(id);
        dynamicObject.setExt(extendProperties);
        dynamicObject.setSerialNo(PreferenceManager.getSerialNo());
        dynamicObject.setDeviceNO(TerminalBaseInfoDaoManager.getInstance().getTerminalDevice());
        dynamicObject.setContent(content);
        Log.e("harisucici","content:"+bytesToHex(content));
        byte[] dataByte = transform.transformObjectToByteArray(dynamicObject);
        String data = bytesToHexString(dataByte);
        Log.e("harisucici","data:"+data);
        Log.e("harisucici","data.length():"+data.length());
        // TODO 计算加密
        TerminalBaseInfo baseInfo = TerminalBaseInfoDaoManager.getInstance().getTerminalBaseInfo();
        try {
            String cert = baseInfo.getCert();
            String certPassword = AESUtil.aesDecrypt(baseInfo.getCertPassword());
            PrivateKey privateKey = new PassUtil().getDevCAInfo(cert, certPassword);
            if (privateKey == null) {
                privateKey = new PassUtil().getDevCAInfo(cert, certPassword);
            }

            // 方法1
            byte[] checkCode = sign(data, 0, privateKey);
            Log.e("harisucici","checkCode:"+bytesToHex(checkCode));
            Log.e("harisucici","checkCode.length:"+checkCode.length);
            dynamicObject.setCheckCode(checkCode);

            // 方法2
//            ISign sign = new Sign();
//            String checkCodeString2 = sign.sign(data, 0, privateKey);
//
//            URLEncoder.encode(checkCodeString2, "utf-8");
//            byte[] checkCode2 = checkCodeString2.getBytes();
//            dynamicObject.setCheckCode(checkCode2);
//
//            IVerify verify = new Verify();
////            X509Certificate x509Certificate = getDevCAInfo(cert, certPassword);
//            byte [] cabuf =Base64.decodeBase64(data);
//            KeyStore keyStore = KeyStore.getInstance("PKCS12");
//            keyStore.load(new ByteArrayInputStream(cabuf), certPassword.toCharArray());
//            Enumeration<String> aliases = keyStore.aliases();
//            if (!aliases.hasMoreElements()) {
//                throw new RuntimeException("no alias found");
//            }
//            String alias = aliases.nextElement();
//            X509Certificate x509Certificate = (X509Certificate) keyStore.getCertificate(alias);
//
//            boolean ok = verify.verify(data, 0, checkCodeString, x509Certificate);
//            boolean b = ok;


        } catch (Exception e) {
            ToastUtil.showToast(TerminalApplication.getTerminalContext(), "签名错误");
            e.printStackTrace();
        }
        req.setObject(dynamicObject);
        return req;
    }
    private  byte[] toBE(long data) {
        byte[] buffer = new byte[]{(byte)((int)(data >>> 24)), (byte)((int)(data >>> 16)), (byte)((int)(data >>> 8)), (byte)((int)(data >>> 0))};
        return buffer;
    }
    private  byte[] sign(String data, long timestamp, PrivateKey privateKey) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            md.update(data.getBytes("utf-8"));
            if(timestamp>0){
                md.update(toBE(timestamp));
            }
            byte[] hash = md.digest();
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(1, privateKey);
            byte[] encrypted = cipher.doFinal(hash);
            return encrypted;
        } catch (Exception var8) {
            var8.printStackTrace();
            return null;
        }
    }
    public X509Certificate getDevCAInfo(String cert, String certPassword) throws Exception {
        char[] password = certPassword.toCharArray();
        byte[] cabuf = Base64.decode(cert, Base64.DEFAULT);
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        keyStore.load(new ByteArrayInputStream(cabuf), password);
        Enumeration aliases = keyStore.aliases();
        if (!aliases.hasMoreElements()) {
            throw new RuntimeException("no alias found");
        } else {
            String alias = (String) aliases.nextElement();
            X509Certificate x509Certificate = (X509Certificate) keyStore.getCertificate(alias);
            return x509Certificate;
        }

    }

    private String byteArrayToHexString(byte[] content) {
        StringBuilder sb = new StringBuilder();
        for (byte b : content) {
            sb.append(String.format("%02X ", b).trim());
        }
        return sb.toString().toUpperCase();
    }

    private String bytesToHex(byte[] bytes) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            if (hex.length() < 2) {
                sb.append(0);
            }
            sb.append(hex);
        }
        return sb.toString();
    }
    public static String bytesToHexString(byte... src) {
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }
    /**
     * 构建上行透传对象 中心查询学时
     *
     * @param msg
     * @param isAddMsg     true 补传消息；
     * @param isNeedAnswer true 需要服务器应答
     * @return
     */
    public Terminal0x0900Request buildTerminal0x0900Request(TimeTerminalTransmissionMessage msg, int serialNo, boolean isAddMsg, boolean isNeedAnswer) {

        Terminal0x0900Request req = new Terminal0x0900Request();
        DynamicObject dynamicObject = new DynamicObject();
        int id = idMapper.getId(msg.getClass());
        int extendProperties = getExt(isAddMsg, isNeedAnswer);

        Transform transform = new DefaultTransform();
        byte[] content = transform.transformObjectToByteArray(msg);
        dynamicObject.setId(id);
        dynamicObject.setExt(extendProperties);
        dynamicObject.setSerialNo(serialNo);
        dynamicObject.setDeviceNO(TerminalBaseInfoDaoManager.getInstance().getTerminalDevice());
        dynamicObject.setContent(content);
        String cert = "111";
        // TODO 计算加密dynamicObject.setCheckCode(checkCode);
//        ByteUtils.shortToBytes()
        String checkCode = "";
        req.setObject(dynamicObject);
        return req;
    }

    public int getExt(boolean isAddMsg, boolean isNeedAnswer) {
        byte[] data = new byte[2];
        BitSet bs = new BitSet();
        if (isAddMsg) {
            bs.set(0);
        }
        if (isNeedAnswer) {
            bs.set(1);
        }
        data = bitSet2ByteArray(bs);
        ByteBuffer bf = ByteBuffer.allocate(2);
        if (data.length > 1) {
            bf.put(data[1]);
        } else {
            bf.put((byte) 0);
        }
        bf.put(data[0]);
        bf.flip();
        return bf.getShort();
    }

    public byte[] bitSet2ByteArray(BitSet bits) {
        byte[] bytes = new byte[bits.length() / 8 + 1];
        for (int i = 0; i < bits.length(); i++) {
            if (bits.get(i)) {
                bytes[bytes.length - i / 8 - 1] |= 1 << (i % 8);
            }
        }
        return bytes;
    }
}
